﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Is.Net {
/**
 * Calculates the amount of money you  pay the government for owning your car, twice a year.
 * The tax is based on the weight of the vehicle. Note that current regulations dictate that
 * vehicles < 400kgs in weight are not taxed. this calculator does not take that into account.
 * 
 * The basis for these calculations can be found at:
 * 
 * http://www.rsk.is/einstakl/skattar/bifreida
 * 
 * @author Hugi Thordarson
 * @converted to C# Ingi Gauti Ragnarsson
 * 
 * TODO: Even though this class is currently only used to calculate estimates, monetary values should be represented by BigDecimal for optimal accuracy.
 */

public class RoadTaxCalculator {

        /**
         * The tax can never be lower than this amount.
         */
        private static readonly int MIN_AMOUNT_DUE = 4227;

        /**
         * The tax can never be higher than this amount.
         */
        private static readonly int MAX_AMOUNT_DUE = 50976;

        /**
         * Kilograms below or at this number cost FIRST_CATEGORY_PRICE.
         */
        private static readonly double FIRST_CATEGORY_WEIGHT = 1000.0;

        /**
         * Kilograms below or at this number + FIRST_CATEGORY_WEIGHT cost SECOND_CATEGORY_PRICE.
         */
        private static readonly double SECOND_CATEGORY_WEIGHT = 2000.0;

        /**
         * Amount paid for every kg under 1000 kg.
         */
        private static readonly double FIRST_CATEGORY_PRICE = 8.45;

        /**
         * Amount paid for every kg between 1001 and 3000 kg.
         */
        private static readonly double SECOND_CATEGORY_PRICE = 11.40;

        /**
         * Amount paid for every started ton of the vehicle's weight after 3 tons.
         */
        private static readonly double THIRD_CATEGORY_PRICE = 2818.0;

        /**
         * The amount you pay is based on the weight of the vehicle.
         */
        private int _weight;

        /**
         * Constructs a new calculator instance. 
         * 
         * @param weight The weight of the vehicle.
         */
        public RoadTaxCalculator( int weight ) {
                SetWeight( weight );
        }

        /**
         * @param value the weight to use for calculations.
         */
        private void SetWeight( int value ) {
                _weight = value;
        }

        /**
         * @return the weight of the vehicle.
         */
        public int Weight {
			get { return _weight; }
        }

        /**
         * @return the total amount due.
         */
        public int Calculate() {
                double result = FirstAmount() + SecondAmount() + ThirdAmount();

                if( result < MIN_AMOUNT_DUE ) {
                        return MIN_AMOUNT_DUE;
                }

                if( result > MAX_AMOUNT_DUE ) {
                        return MAX_AMOUNT_DUE;
                }

                return (int)Math.Floor( result );
        }

        /**
         * @return The part of the tax paid for weight < FIRST_CATEGORY_WEIGHT.
         */
        private double FirstAmount() {
                if( Weight < FIRST_CATEGORY_WEIGHT ) {
                        return Weight * FIRST_CATEGORY_PRICE;
                }

                return FIRST_CATEGORY_WEIGHT * FIRST_CATEGORY_PRICE;
        }

        /**
         * @return The part of the tax paid for weight between FIRST_CATEGORY_WEIGHT and FIRST_CATEGORY_WEIGHT + SECOND_CATEGORY_WEIGHT
         */
        private double SecondAmount() {

                if( Weight <= FIRST_CATEGORY_WEIGHT ) {
                        return 0.0;
                }

                if( Weight < FIRST_CATEGORY_WEIGHT + SECOND_CATEGORY_WEIGHT ) {
                        return (Weight - FIRST_CATEGORY_WEIGHT) * SECOND_CATEGORY_PRICE;
                }

                return SECOND_CATEGORY_WEIGHT * SECOND_CATEGORY_PRICE;
        }

        /**
         * @return The part of the tax paid for weight above FIRST_CATEGORY_WEIGHT + SECOND_CATEGORY_WEIGHT
         */
        private double ThirdAmount() {

                if( Weight <= (FIRST_CATEGORY_WEIGHT + SECOND_CATEGORY_WEIGHT) ) {
                        return 0.0;
                }

                double weightInTons = Weight / 1000.0;
                double tonsToUseForCalculation = weightInTons - (FIRST_CATEGORY_WEIGHT + SECOND_CATEGORY_WEIGHT) / 1000;
                tonsToUseForCalculation = Math.Ceiling( tonsToUseForCalculation );

                return tonsToUseForCalculation * THIRD_CATEGORY_PRICE;
        }
}

}
